package com.xb.loan.cashier.biz.task.unionpay;

import com.xb.loan.cashier.biz.dao.bean.CashierPayChannel;
import com.xb.loan.cashier.biz.pay.unionpay.UnionPayAcpService;
import com.xb.loan.cashier.biz.pay.unionpay.UnionPayConstants;
import com.xb.loan.cashier.biz.service.CashierChargeOrderService;
import com.xb.loan.cashier.biz.service.CashierPayChannelService;
import com.xb.loan.cashier.biz.service.CashierPlatPaytypeService;
import com.xb.loan.cashier.biz.task.ThirdQueryChargeTask;
import com.xb.loan.cashier.biz.task.plat.PushChargeTask;
import com.xb.loan.cashier.service.constant.ICashierEnumConst;
import com.xb.loan.util.DateHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 查询银联支付订单状态任务
 */
@Component(value="unionPayQueryChargeTask")
@Scope(value="prototype")
public class UnionPayQueryChargeTask extends ThirdQueryChargeTask {
    private static final Logger log = LoggerFactory.getLogger(UnionPayQueryChargeTask.class);
    
    @Autowired
    private CashierChargeOrderService cashierChargeOrderService;
    @Autowired
    private CashierPayChannelService cashierPayChannelService;
    @Autowired
    private CashierPlatPaytypeService cashierPlatPaytypeService;
    
    @Override
    public void execute() {
        log.info("UnionPayQueryChargeTask.execute 开始处理订单 orderId="+cashierChargeOrder.getOrderId()+
                ",platId="+cashierChargeOrder.getPlatId()+",partnerId="+
                cashierChargeOrder.getPartnerId()+",payChannelType="+cashierChargeOrder.getPayChannelType());
                
        //查询支付渠道基本信息
        CashierPayChannel cpc = cashierPayChannelService.queryByChannelId(cashierChargeOrder.getPayChannelId());
        
        if (cpc == null) {
            log.info("UnionPayQueryChargeTask.execute 支付渠道信息不存在 platId="+
                    cashierChargeOrder.getPlatId()+",payChannelType="+cashierChargeOrder.getPayChannelType());
            return;
        }
        
        Map<String, String> data = new HashMap<String, String>();
        
        /***银联全渠道系统，产品参数，除了encoding自行选择外其他不需修改***/
        data.put("version", UnionPayConstants.VERSION);         //版本号
        data.put("encoding", UnionPayConstants.UTF_8_ENCODING); //字符集编码 可以使用UTF-8,GBK两种方式
        data.put("signMethod", "01");                           //签名方法 目前只支持01-RSA方式证书加密
        data.put("txnType", "00");                              //交易类型00：查询交易
        data.put("txnSubType", "00");                           //交易子类型  默认00
        data.put("bizType", "000201");                          //业务类型 B2C网关支付，手机wap支付
        
        /***商户接入参数***/
        data.put("merId", cpc.getChannelUser());                //商户号码，请改成自己申请的商户号或者open上注册得来的777商户号测试
        data.put("accessType", "0");                            //接入类型，商户接入固定填0，不需修改
        
        /***要调通交易以下字段必须修改***/
        //商户订单号，每次发交易测试需修改为被查询的交易的订单号
        data.put("orderId", cashierChargeOrder.getOrderId());
        //订单发送时间，每次发交易测试需修改为被查询的交易的订单发送时间
        data.put("txnTime", DateHelper.formatDate("yyyyMMddHHmmss", cashierChargeOrder.getCreateTime()));
        
        /**请求参数设置完毕，以下对请求参数进行签名并发送http post请求，接收同步应答报文**/
        
        //报文中certId,signature的值是在signData方法中获取并自动赋值的，只要证书配置正确即可
        Map<String, String> reqData = new HashMap<String, String>();
        
        try {
            
            reqData = UnionPayAcpService.sign(data,UnionPayConstants.UTF_8_ENCODING);
            
        } catch (Exception e) {
            
            log.error(e.getMessage(), e);
            return ;
        }
        
        // 交易请求url
        String url = cpc.getQueryUrl();
        
        Map<String, String> rspData = UnionPayAcpService.post(reqData , url , UnionPayConstants.UTF_8_ENCODING);
        
        /**对应答码的处理 **/
        
        if(rspData.isEmpty()){
            //如果查询返回为空，则请求失败
            log.info("UnionPayQueryChargeTask.execute 查询订单结果无返回 orderId="+cashierChargeOrder.getOrderId());
            return ;
        }
        
        if(!UnionPayAcpService.validate(rspData, UnionPayConstants.UTF_8_ENCODING)){
            //验证签名错误
            log.info("UnionPayQueryChargeTask.execute 验证签名错误 orderId="+cashierChargeOrder.getOrderId());
            return;
        }
        
        //应答码
        String respCode = rspData.get("respCode");
        String respMsg = rspData.get("respMsg");
        
        if("00".equals(respCode)){
            
            //处理订单交易状态
            dealOrderStatus(rspData);
            
        }else if("34".equals(respCode)){
            
            //查无此交易
            validatOrderOverTime(respCode , respMsg);
            
        }else{
            
            //查询交易本身失败，或者未查到原交易
            log.info("UnionPayQueryChargeTask.execute 查询交易错误orderId="+cashierChargeOrder.getOrderId() + 
                    ",respCode=" + respCode + ",respMsg=" + respMsg);
        }
    }
    
    private void dealOrderStatus(Map<String, String> rspData){
        
        //交易金额,单位为分
        double txnAmt = Double.parseDouble(rspData.get("txnAmt"));
        
        if (txnAmt != cashierChargeOrder.getMoney() * 100) {
            
            log.info("UnionPayQueryChargeTask 银联返回金额与收银台不一致  orderId="+cashierChargeOrder.getOrderId()+
                    ",txnAmt="+txnAmt+",money="+cashierChargeOrder.getMoney());
            return ;
        }
        
        //处理被查询交易的应答码逻辑
        String origRespCode = rspData.get("origRespCode");
        //在交易状态查询时返回此域，默认返回应答描述+7位应答码
        String origRespMsg = rspData.get("origRespMsg");
        
        String errorCode = null;
        String errorMsg = null;
        
        //订单状态
        int status = 0;
        
        if("00".equals(origRespCode)){
            //交易成功
            status = ICashierEnumConst.CashierChargeStatus.SUCCESS.getStatus();
            
        }else if("03".equals(origRespCode) ||
                "04".equals(origRespCode) ||
                "05".equals(origRespCode) ){
            /*
             * 需要再次发送查询交易请求
             * 
             * 03:交易通讯超时，请发起查询交易
             * 04:交易状态未明，请查询对账结果
             * 05:交易已受理，请稍后查询交易结果
             */
            
            log.info("UnionPayQueryChargeTask.dealOrderStatus 查询交易请求异常orderId="+cashierChargeOrder.getOrderId() + 
                    ",origRespCode=" + origRespCode + ",origRespMsg=" + origRespMsg);
            return ;
            
        }else{
            
            //其他应答码为失败
            status = ICashierEnumConst.CashierChargeStatus.FAIL.getStatus();
            
            errorCode = origRespCode;
            errorMsg = origRespMsg;
        }
        
        //查询流水号,由银联返回，用于在后续类交易中唯一标识一笔交易
        String queryId = rspData.get("queryId");
        //交易传输时间,（MMDDHHmmss）24小时制收单机构对账时使用
        String traceTime = rspData.get("traceTime");
        
        try {
            
            //转换交易时间格式为yyyy-MM-dd HH:mm:ss
            Date tradeTime = DateHelper.convertToDate("yyyyMMddHHmmss", DateHelper.formatDate("yyyy", new Date()) + traceTime);
            traceTime = DateHelper.DateToString(null, tradeTime);
            
        } catch (ParseException e) {
            e.printStackTrace();
        }
        
        int res = cashierChargeOrderService.updateByOrderId(null, null, cashierChargeOrder.getOrderId(), traceTime, 
                status, queryId , errorCode, errorMsg);
        
        if(res > 0){
            
            PushChargeTask pct = (PushChargeTask)ctx.getBean("pushChargeTask");
            cashierChargeOrder.setStatus(status);
            pct.setCashierChargeOrder(cashierChargeOrder);
            pct.execute();
            
            log.info("UnionPayQueryChargeTask.dealOrderStatus 更新状态status="+ status +
                    ",orderId=" + cashierChargeOrder.getOrderId()+
                    ",platId=" + cashierChargeOrder.getPlatId()+
                    ",partnerId=" + cashierChargeOrder.getPartnerId());
        }
    }
    
    private void validatOrderOverTime(String respCode , String respMsg){
        
        log.info("UnionPayQueryChargeTask.validatOrderOverTime orderId="+cashierChargeOrder.getOrderId() + 
                ",respCode=" + respCode + ",respMsg=" + respMsg);
        
        if(!isTimeOut()){
            //未超时，暂时不处理订单状态
            log.info("UnionPayQueryChargeTask.validatOrderOverTime orderId="+
                    cashierChargeOrder.getOrderId() + ",银联订单不存在且未超时,暂不做处理!");
            return;
        }
        log.info("UnionPayQueryChargeTask.validatOrderOverTime orderId="+
                cashierChargeOrder.getOrderId() + ",银联订单不存在且创建已超时,该订单将会被处理为失败!");
        
        //超时订单，置为失败
        int status = ICashierEnumConst.CashierChargeStatus.FAIL.getStatus();
        
        int res = cashierChargeOrderService.updateByOrderId(null, null, cashierChargeOrder.getOrderId(), null, 
                status, null , respCode, respMsg);
        
        if(res > 0){
            
            PushChargeTask pct = (PushChargeTask)ctx.getBean("pushChargeTask");
            cashierChargeOrder.setStatus(status);
            pct.setCashierChargeOrder(cashierChargeOrder);
            pct.execute();
            
            log.info("UnionPayQueryChargeTask.validatOrderOverTime 更新状态status="+ status +
                    ",orderId=" + cashierChargeOrder.getOrderId()+
                    ",platId=" + cashierChargeOrder.getPlatId()+
                    ",partnerId=" + cashierChargeOrder.getPartnerId());
        }
    }
}
